package org.foreningsgatan.modular.terrain;

import java.awt.Color;
import java.awt.image.BufferedImage;

import org.foreningsgatan.modular.terrain.model.Tile;

/**
 * 
 * Copyright (c) 2008 Joakim Back
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * @author Joakim Back
 *
 */
public class ImageGenerator 
{
	private int size;
	
	public static Color[] COLORS = {
		Color.BLUE.darker(), 
		Color.BLUE, 
		Color.YELLOW, 
		new Color(192, 255, 0), 
		Color.GREEN
	};
	
	public ImageGenerator(int size) {
		this.size = size;
	}
	
	public static Color getColor(Object o) {
		try {
			return COLORS[(Integer) o];
		} catch (Exception e) {
			return Color.BLACK; 
		}
	}
	
	private Color blendColor(Color c1, Color c2, Color c3, Color c4, double fx, double fy) {
		double ifx = (1 - fx);
		
		double ify = (1 - fy);
		
		double r = 
			(fx * fy * c1.getRed()) + (ifx * fy * c2.getRed()) +
			(fx * ify * c3.getRed()) + (ifx * ify * c4.getRed());
		
		double g = 
			(fx * fy * c1.getGreen()) + (ifx * fy * c2.getGreen()) +
			(fx * ify * c3.getGreen()) + (ifx * ify * c4.getGreen());
		
		double b = 
			(fx * fy * c1.getBlue()) + (ifx * fy * c2.getBlue()) +
			(fx * ify * c3.getBlue()) + (ifx * ify * c4.getBlue());
		
		double a =
			(fx * fy * c1.getAlpha()) + (ifx * fy * c2.getAlpha()) +
			(fx * ify * c3.getAlpha()) + (ifx * ify * c4.getAlpha());
		
		return new Color((int) r, (int) g, (int) b, (int) a);
	}
	
	private BufferedImage generateImage(Tile tile) {
		BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
		
		for (int y = 0; y < size; y++) {
			for (int x = 0; x < size; x++) {
				double fx = 1.0 - (double) x / size;
				double fy = 1.0 - (double) y / size;
				
				Color c = blendColor(getColor(tile.getUpperLeft()), getColor(tile.getUpperRight()), 
						getColor(tile.getLowerLeft()), getColor(tile.getLowerRight()), fx, fy); 
				
				image.setRGB(x, y, c.getRGB());
			}
		}
		
		return image;
	}
	
	private Color blend(Color c1, Color c2) {
		double f = (double) c2.getAlpha() / 255;
		
		double r = (1 - f) * c1.getRed() + f * c2.getRed();
		double g = (1 - f) * c1.getGreen() + f * c2.getGreen();
		double b = (1 - f) * c1.getBlue() + f * c2.getBlue();
		
		return new Color((int) r, (int) g, (int) b);
	}
	
	public BufferedImage generateImage(Integer cInt, boolean upperLeft, boolean upperRight, boolean lowerLeft, boolean lowerRight) {
		BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
		
		if (!upperLeft && !upperRight && !lowerLeft && !lowerRight) {
			return image;
		}
		
		Color color = getColor(cInt);
		Color transparent = new Color(color.getRed(), color.getGreen(), color.getBlue(), 0);
		
		for (int y = 0; y < size; y++) {
			for (int x = 0; x < size; x++) {
				double fx = 1.0 - (double) x / size;
				double fy = 1.0 - (double) y / size;
				
				Color cUL = (upperLeft) ? color : transparent;
				Color cUR = (upperRight) ? color : transparent;
				Color cLL = (lowerLeft) ? color : transparent;
				Color cLR = (lowerRight) ? color : transparent;
				
				Color c = blendColor(cUL, cUR, cLL,  cLR, fx, fy); 
				
				Color result = blend(new Color(image.getRGB(x, y)), c);
				
				image.setRGB(x, y, result.getRGB());
			}
		}
		
		return image;
	}
	
	public BufferedImage generate(Tile tile) {
		return generateImage(tile);
	}
}
